﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Webcrawler;
using Graph;
using System.Threading;
using System.Threading.Tasks;


namespace WebcrawlerController
{
    public class WebCrawlerCTR
    {
        private IBasicGraph _graph;
        private int maxDepth;
        private bool thisDomainOnly;
        private List<Link> _listLink = new List<Link>();
    

        private string html;
        private string headers;
       
        private string[] search = {"/", "/index.php", "/index.html", "/index.htm", "/default.asp", "/default.aspx"};

        #region Constructor
        
        public WebCrawlerCTR()
        {
            this._graph = new BasicGraph();
            this.maxDepth = 0;
            this.thisDomainOnly = true;
            
        }
        #endregion

        #region Properties

        public IBasicGraph _Graph
        {
            get { return _graph; }
            set { _graph = value; }
        }

        public int MaxDepth
        {
            get { return maxDepth; }
            set { maxDepth = value; }
        }

        public bool ThisDomainOnly
        {
            get { return thisDomainOnly; }
            set { thisDomainOnly = value; }
        }

        public string Html
        {
            get { return html; }
            set { html = value; }
        }

        public string Headers
        {
            get { return headers; }
            set { headers = value; }
        }


        #endregion

        /// <summary>
        /// Metoden gør følgende:
        /// 1. For hver knude i en graf, tilføjer metoden en ny SortedList til levelList
        /// 2. Ændrer thisDomainOnly til parameteret thisDomainOnly
        /// 3. Ændrer maxDepth til parameteret levels
        /// 4. Kalder klassen Link constructor med parameteret url og tempname "MainPage"
        /// 5. Kører metoden CombineCrawlerLinks med parameterne (link, null, 0)
        /// 6. Metoden opretter også varialen i, som vokser hver gang while loopet kører, men bruges ellers ikke
        /// </summary>
        /// <param name="url"></param>
        /// <param name="levels"></param>
        /// <param name="thisDomainOnly"></param>
      
        
        public Link Start(string url, int levels, bool thisDomainOnly)
        {
            this.thisDomainOnly = thisDomainOnly;
            this.maxDepth = levels;
            
            _graph.Clear();
            _listLink.Clear();
            this.headers = "";
            this.html = "";
            Link link = new Link(url, "MainPage");
            CombineCrawlerLinks(link, null, 0);
            return link;
        }

        /// <summary>
        /// Metoden gør en af følgende:
        /// 1. Hvis depth er større end maxDepth: Intet.
        /// 2. Hvis depth ikke er større end maxDepth: Laver en knude ud fra parameterne link og depth.
        /// 3. Hvis depth ikke er større end maxDepth og grafen ikke har den nye knude: Tilføj knuden. Lav en instans af Cralwer. Kører metoden Crawler.CrawlPage() og sig selv igen.
        /// 4. Hvis depth ikke er større end maxDepth og grafen ikke har den nye knude og parent ikke er null: Tilføjer en kant fra den nye knude til parent.
        /// </summary>
        /// <param name="link"></param>
        /// <param name="parent"></param>
        /// <param name="depth"></param>

        public void CombineCrawlerLinks(Link link, Vertex parent, int depth)
        {

                if (depth <= maxDepth)
                {
                    Vertex _vertex = new Vertex(link);

                    if (!_graph.ContainsVertex(_vertex))
                    {
                        _graph.AddVertex(_vertex);

                        Crawler _crawler = new Crawler();
                        if (parent != null)
                        {
                            _graph.AddEdge(parent, _vertex);
                        }

                        int count = _crawler.CrawlPage(link.Url, thisDomainOnly);

                        if (this.html.Length == 0 && this.headers.Length == 0)
                        {
                            this.html = _crawler.Content;
                            this.headers = _crawler.Headers;
                        }

                        if (count >= 0)
                        {
                            MakeTreeView(link, _crawler.Links);
                            depth++;
                            
                            //Console.WriteLine("threadId {0}", Thread.CurrentThread.ManagedThreadId);
                            //foreach (Link _link in _crawler.Links)
                            
                            Parallel.ForEach(_crawler.Links, _link =>
                            {
                                CombineCrawlerLinks(_link, _vertex, depth);
                            });
                        }

                    }
                    else
                    {
                        if (!_graph.ContainsEdge(parent, _vertex))
                        {
                            _graph.AddEdge(parent, _vertex);
                        }

                    }
                }
            }
        

        private void MakeTreeView(Link link, List<Link> _links)
        {
            
            link.LinkList = _links; //Tilføjer alle under links til Linket
            _listLink.Add(link);
        }

        //public void controletreeview()
        //{
        //    Boolean found = false;
        //    while (_graph.Vertices().MoveNext() || found)
        //    {
        //        Vertex vertex = (Vertex)_graph.Vertices().Current;
        //        if (vertex.depths == 0)
        //        {
        //            found = true;
        //            Bfs(vertex);
        //        }
        //    }
        //}
        /// <summary>
        /// Bredte først søgning.
        /// </summary>
        /// <param name="v"></param>
        public void RecuPrintTree(Vertex v)
        {//BFS
            Queue<Vertex> q = new Queue<Vertex>();
            v.Mark = true;
            q.Enqueue(v);
            while (q.Count > 0)
            {
                Vertex w = q.Dequeue();
                foreach (Vertex u in _graph.GetAdjacencies(w))
                {
                    if (!u.Mark)
                    {
                        u.Mark = true;
                        q.Enqueue(u);
                    }
                }
            }
        }

        public IBasicGraph GetGraph()
        {
            return _Graph;
        }


        //public void Dfs(Vertex v)
        //{
        //    v.Mark = true;
        //    Console.WriteLine(v.Name);
        //    foreach (Vertex u in GetAdjacencies(v))
        //    {
        //        if (!u.Mark)
        //        {
        //            Dfs(u);
        //        }
        //    }
        //}
        
            
        public List<Link> ListLink    
        {
            get { return _listLink; }
            set { _listLink = value; }
        }
        
        
    }
}

